package la.bbs558.handler;

import cn.hutool.core.date.DateUtil;
import la.bbs558.context.PointContext;
import la.bbs558.entity.UserPointsLog;
import la.bbs558.entity.enums.ActionPeriod;
import la.bbs558.entity.enums.PointsOptType;
import la.bbs558.entity.enums.UserOpt;
import la.bbs558.service.UserDataService;
import la.bbs558.service.UserPointsLogService;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.Resource;
import java.util.Date;
import java.util.Optional;

@Slf4j
public abstract class PointsHandler {
    @Resource
    protected UserDataService userDataService;
    @Resource
    protected UserPointsLogService userPointsLogService;

    final public void action(PointContext context) {
        Long userId = context.getUserId();
        int maxTimes = maxTimes();
        PointsOptType optType = context.getOptType();
        UserOpt optDetail = context.getOptDetail();
        Long optId = context.getOptId();
        Integer exist = userPointsLogService.lambdaQuery()
                .eq(UserPointsLog::getUserId, userId)
                .eq(UserPointsLog::getOptType, optType.name())
                .eq(UserPointsLog::getOptDetail, optDetail.name())
                .eq(UserPointsLog::getOptId, optId)
                .count();
        if(exist > 0){
            return;
        }
        if( maxTimes == 0 || this.currentTimes(context) < maxTimes){
            int points = points();
            userDataService.updatePoints(userId, points);
            UserPointsLog userPointsLog = new UserPointsLog();
            userPointsLog.setUserId(userId);
            userPointsLog.setPoints(points);
            userPointsLog.setOptId(context.getOptId());
            userPointsLog.setOptType(optType.name());
            userPointsLog.setOptDetail(optDetail.name());
            userPointsLogService.save(userPointsLog);

        }
    }

    final protected int selectDayOptCnt(PointContext context){
        Long userId = context.getUserId();
        PointsOptType optType = context.getOptType();
        Date date = new Date();
        int maxTimes = maxTimes();
        Integer count = userPointsLogService.lambdaQuery()
                .select(UserPointsLog::getOptType)
                .eq(UserPointsLog::getUserId, userId)
                .eq(UserPointsLog::getOptType, optType.name())
                .between(UserPointsLog::getCreateTime, DateUtil.beginOfDay(date), DateUtil.endOfDay(date))
                .groupBy(UserPointsLog::getOptType)
                .last("limit " + maxTimes)
                .list().size();
        return Optional.of(count).orElse(0);
    }

    protected abstract int currentTimes(PointContext context);
    protected abstract int maxTimes();
    protected abstract int points();
    protected abstract ActionPeriod period();
}
